import path from 'node:path';
import fs from 'node:fs';
import { Field } from './types.js';
import { resolveModelPath, readFile, ensureDir, writeFileOnce, updateExportFile } from './utils.js';
import { renderTemplate } from './template-engine.js';
import { pascalCase } from 'change-case';

const TYPE_MAP: Record<string, string> = {
  string: 'string',
  number: 'number',
  boolean: 'boolean',
  date: 'Date',
};

function normalizeType(t: string): string {
  const k = t.toLowerCase();
  return TYPE_MAP[k] ?? 'string';
}

export async function generateFromFile(modelOrPath: string) {
  const filePath = resolveModelPath(modelOrPath);
  const content = readFile(filePath);

  // Try to grab class name (e.g., export class Activation extends Model<Activation>)
  const classMatch = content.match(/export\s+class\s+(\w+)/);
  const className = classMatch ? classMatch[1] : path.basename(filePath).replace(/\.model\.ts$/, '');
  const modelName = pascalCase(className);

  // Naive column parse: lines like "  fieldName!: string;" possibly after @Column
  const fieldMatches = [...content.matchAll(/@Column[\s\S]*?\n\s*(\w+)\!?\s*:\s*([\w\[\]]+)/g)];
  const fields: Field[] = fieldMatches.map(m => ({ name: m[1], type: normalizeType(m[2]) }));

  if (!fields.length) {
    // Fallback: parse all public properties
    const propMatches = [...content.matchAll(/\n\s*(\w+)\!?\s*:\s*([\w\[\]]+)\s*;/g)];
    for (const m of propMatches) {
      if (m[1] !== 'id') fields.push({ name: m[1], type: normalizeType(m[2]) });
    }
  }

  await generateCRUD(modelName, fields, true, filePath);
}

export async function generateFromAttributes(model: string, attributes: string) {
  const modelName = pascalCase(model);
  const fields: Field[] = attributes.split(',').map(pair => {
    const [name, typeRaw] = pair.split(':');
    return { name: name.trim(), type: normalizeType((typeRaw || 'string').trim()) };
  });
  await generateCRUD(modelName, fields, false);
}

async function generateCRUD(modelName: string, fields: Field[], skipModel: boolean, modelFilePath?: string) {
  const feature = modelName.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, ''); // e.g., activation
  const targetDir = path.resolve(process.cwd(), 'src', 'controller', feature);
  if (fs.existsSync(targetDir)) {
    throw new Error(`Module folder already exists: ${targetDir}`);
  }
  ensureDir(targetDir);

  const tplData = { modelName, feature, fields };

  // dto
  writeFileOnce(path.join(targetDir, `${feature}.dto.ts`), renderTemplate('dto.ts.hbs', tplData));
  // service
  writeFileOnce(path.join(targetDir, `${feature}.service.ts`), renderTemplate('service.ts.hbs', tplData));
  // controller
  writeFileOnce(path.join(targetDir, `${feature}.controller.ts`), renderTemplate('controller.ts.hbs', tplData));
  // module
  writeFileOnce(path.join(targetDir, `${feature}.module.ts`), renderTemplate('module.ts.hbs', tplData));
  // model (if needed)
  if (!skipModel) {
    writeFileOnce(path.join(targetDir, `${feature}.model.ts`), renderTemplate('model.ts.hbs', tplData));
  } else if (modelFilePath) {
    // Copy the original model file to the target directory
    const modelContent = readFile(modelFilePath);
    writeFileOnce(path.join(targetDir, `${feature}.model.ts`), modelContent);
  }

  // 添加模块和模型到对应的导出文件
  const moduleExportPath = path.resolve(process.cwd(), 'src', 'index.export.module.ts');
  const modelExportPath = path.resolve(process.cwd(), 'src', 'index.export.model.ts');
  
  // 更新模块导出文件
  updateExportFile(
    moduleExportPath, 
    `${modelName}Module`, 
    `src/controller/${feature}/${feature}.module`
  );
  
  // 更新模型导出文件
  updateExportFile(
    modelExportPath, 
    modelName, 
    `src/controller/${feature}/${feature}.model`
  );
}
